# -*- coding:utf-8 -*-
# @Time : 21-8-3 下午2:43
# @Author : zdy
# @File : Serial_Com.py
# desc: 采集卡模块
# modify: 2022/5/31 根据ONH，增加翻转功能


import serial.tools.list_ports
from queue import Queue
import threading
import time
import datetime
from Class.Log import log
import random
from importQT import *

datatemp = []
lasttick = 0
lasttick1 = 0
lasttick2 = 0
lasttick3 = 0
class CurvePoints():
    def __init__(self):
        self.ChannelV = list()
        self.m = list()
        self.UpContainer = 0
        self.DIValue = 0

class Serial_com(QObject):
    sigReceiveHex = pyqtSignal(str)
    sigReceive = pyqtSignal(CurvePoints)
    sigInfo = pyqtSignal(str)  # 通讯中状态信号

    def __init__(self, parent=None):
        super().__init__(parent)
        self.ser = serial.Serial()
        self.bufShakeHand = [0xfb, 0xfc, 0xf0, 0xfd, 0xfe]
        self.bufACQ = [0xfb, 0xfc, 0xf1, 0xfd, 0xfe]
        self.bufSingleACQ = [0xfb, 0xfc, 0xf4, 0xfd, 0xfe]
        self.isLinked = False
        self.uDoFlag = 0
        self.portName = "/dev/USB0"
        self.queData = Queue()
        self.stop = False
        self.threadRead = None
        self.threadReceiveCom = None
        self.isLinkedBefore = False  # 记录开启软件后是否连接成功过
        self.inverse = [False] * 48


    # 打开串口
    def open(self):
        try:
            self.ser.port = self.portName
            self.ser.baudrate = 115200
            self.ser.bytesize = 8
            self.ser.stopbits = 1
            self.ser.parity = 'N'
            self.ser.timeout = 1
            self.ser.close()
            if not self.ser.isOpen():
                self.ser.open()
        except Exception as ex:
            self.info(str(ex))
            return False
        if self.isOpen():
            self.info(self.portName + "打开成功")
        else:
            self.info(self.portName + "打开失败")
        return self.isOpen()

    def link_card(self):
        if self.open():
            self.stop = False
            self.data_send(self.bufShakeHand)
            self.ser.flushInput()  # 清除输入缓冲区
            time.sleep(0.1)
            self.threadRead = threading.Thread(target=self.comQueueData_Read)
            self.threadRead.setDaemon(True)
            self.threadReceiveCom = threading.Thread(target=self.data_receive)
            self.threadReceiveCom.setDaemon(True)  # 后台线程
            self.threadReceiveCom.start()
            self.threadRead.start()
            self.data_send(self.bufACQ)
            time.sleep(0.5)
        else:
            self.isLinked = False
        pass

    # 关闭串口
    def close(self):
        """发送握手信号，DO复位，关闭串口"""
        self.stop = True
        time.sleep(0.001)
        try:
            if self.ser.isOpen():
                self.data_send(self.bufShakeHand)
                self.uDoFlag = 0
                self.outputDO()
                time.sleep(1)
                self.ser.close()
        except:
            pass

    def isOpen(self):
        '''返回串口状态'''
        return self.ser.isOpen()

    def data_receive(self):
        t1 = datetime.datetime.now()
        '''接收数据'''
        while not self.stop:
            time.sleep(0.1)
            if not self.ser.is_open:
                continue
            try:
                num = self.ser.inWaiting()
            except:
                self.info("串口waiting异常")
                continue
            if num > 0:
                t1 = datetime.datetime.now()
                data = self.ser.read(num)
                # hex显示
                out_s = ''
                for i in range(0, len(data)):
                    out_s = out_s + '{:02X}'.format(data[i]) + ' '
                    self.queData.put(data[i])
                self.sigReceiveHex.emit(out_s)
            else:
                if self.isLinked:
                    t2 = datetime.datetime.now()
                    if (t2 - t1).seconds > 3:  # 超过3s,收不到数据，认为连接断开
                        self.isLinked = False
                elif self.isLinkedBefore:
                    self.data_send(self.bufACQ)
                    # self.info("长时间收不到数据，重新连接")

    # 发送数据
    def data_send(self, buf):
        if self.ser.isOpen():
            self.ser.write(buf)
            sendbuf = map(lambda x: hex(x), buf)
            str1 = ''.join(sendbuf)
            # self.info("发送" + str1)
            return True
        else:
            return False

    def unLink(self):
        self.close()
        self.isLinked = False

    def outputDO(self):
        bs = [0xff, 0xfe, 0xf2, 0x3, 0x4, 0x5, 0xfb, 0xfa]
        # big:高位在前，即数组0开始，
        bs2 = self.uDoFlag.to_bytes(3, byteorder='big', signed=False)
        bs[3] = bs2[0]
        bs[4] = bs2[1]
        bs[5] = bs2[2]
        return self.data_send(bs)

    def setChannelDO(self, index, bSet):
        if bSet:
            t = 1 << index
            self.uDoFlag = self.uDoFlag | t
        else:
            t = 1 << index
            t = ~t
            self.uDoFlag = self.uDoFlag & t

    def getChannelDO(self, index):
        data = self.uDoFlag
        return (data >> index & 0x01) == 0x01

    def writeChannelAO(self, index, outVolt, delay = True):
        bs = [0xff, 0xfd, 0xf1, 0x3, 0x4, 0x05, 0xfb, 0xfa]
        # big:高位在前，即数组0开始，
        bs[3] = (int(index).to_bytes(length=1, byteorder='big', signed=False))[0]
        a = int((outVolt + 10) / 20 * ((1 << 15) - 1))
        bs1 = a.to_bytes(2, byteorder='big', signed=False)
        bs[4] = bs1[0]
        bs[5] = bs1[1]
        self.data_send(bs)
        if delay:
            time.sleep(0.1)

    def setPortName(self, str):
        self.portName = str

    def comQueueData_Read(self):
        while (self.stop is False):
            time.sleep(0.005)
            if (self.queData.qsize() >= 5):
                header = [0, 0, 0, 0, 0]
                for i in range(0, 5):
                    header[i] = self.queData.get()
                if ((header[0] != 0xfb) or (header[1] != 0xfc)):
                    self.info("帧头错误")
                    pass
                else:
                    count = 0
                    if (header[2] == 0x13 or header[2] == 0x14 or header[2] == 0x19):
                        self.isLinked = True
                        self.isLinkedBefore = True
                        deNum = header[3] - 5;
                        while (self.stop is False) and (self.queData.qsize() < deNum) and (count < 10):
                            count += 1
                            time.sleep(0.01)
                        if self.queData.qsize() < deNum:
                            self.info("数据异常")
                        else:
                            data = [0 for x in range(0, deNum)]
                            for i in range(0, deNum):
                                data[i] = self.queData.get()
                            self.ParseBuffer(data)
                    if (header[2] == 0xf1):
                        self.isLinked = True
                        self.isLinkedBefore = True
                        deNum = 2
                        while (self.stop is False) and (self.queData.qsize() < deNum) and (count < 10):
                            count += 1
                            time.sleep(0.01)
                        if self.queData.qsize() < deNum:
                            self.info("数据异常")
                            pass
                        else:
                            for i in range(0, deNum):
                                self.queData.get()
                    if (header[2] == 0xf0):
                        self.info("握手信号")
                        self.isLinked = True
                        self.isLinkedBefore = True
                        pass
                    if (header[2] == 0xe0):
                        self.isLinked = True
                        self.info("上电信号")
                        pass
                    if header[2] in [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]:
                        self.info("配置信息")
                        pass

    def ParseBuffer(self, data):
        global lasttick
        global lasttic
        global lasttick1
        global lasttick2
        global lasttick3
        global datatemp
        pts = CurvePoints()
        pts.ChannelV.clear()  # 必须加这句，不然多次进入该函数，用的都是同一地址
        pts.UpContainer = data[0]
        pts.DIValue = int.from_bytes(data[1:1 + 2], byteorder='big', signed=False)
        noise = 0#0.00015 * (random.random())
        for i in range(48):
            uv = 0.0
            # cardIndex = int(i/16)
            # channel = i%16
            # if cardIndex <2:
            #     if channel <8:
            #         startIndex = channel *3 + cardIndex *32 + cardIndex +4
            #         uv = int.from_bytes(data[startIndex:startIndex + 3], byteorder='big', signed=False)
            #         pts.ChannelV.append(uv * 20.0 / 65535 / 128 - 10 + noise)
            #     else:
            #         startIndex =  channel  + cardIndex *32 + cardIndex +20
            #         uv = int.from_bytes(data[startIndex:startIndex + 1], byteorder='big', signed=False)
            #         pts.ChannelV.append(uv * 20.0 / 256 - 10)
            # else:
            #     startIndex = 70 + channel*2
            #     uv = int.from_bytes(data[startIndex:startIndex + 2], byteorder='big', signed=False)
            #     pts.ChannelV.append(uv * 20.0 / 65535 - 10)

            if i < 32:
                j = i % 16
                if j < 8:
                    num = 3 * j + 4 + int(j / 16)
                    uv = int.from_bytes(data[num:num + 3], byteorder='big', signed=False)
                    pts.ChannelV.append(uv * 20.0 / 65535 / 128 - 10 + noise)

                else:
                    num = 1 * j + 4 + int(j / 16)
                    uv = int.from_bytes(data[num:num + 1], byteorder='big', signed=False)
                    pts.ChannelV.append(uv * 20.0 / 256 - 10)
            else:
                num = 2 * i + 4 + int(i / 16)
                uv = int.from_bytes(data[num:num + 2], byteorder='big', signed=False)
                pts.ChannelV.append(uv * 20.0 / 65535 - 10)
            if self.inverse[i]:
                pts.ChannelV[i] = -pts.ChannelV[i]
        # region 注释
        # UpContainer1 = data[3]
        # UpContainer2 = data[36]
        # UpContainer3 = data[69]
        # if len(datatemp) ==12:
        #     if abs(datatemp[8] - pts.ChannelV[32]) > 0.2 or abs(datatemp[9] - pts.ChannelV[33]) > 0.2 or \
        #             abs(datatemp[10] - pts.ChannelV[34]) > 0.2 or abs(datatemp[11] - pts.ChannelV[35]) > 0.2:
        #         print(datetime.datetime.now().strftime("%H:%M:%S")+ "突变上一点," + str(lasttick) + "," +
        #               str(lasttick1) + "," + ('%.6f' % datatemp[0]) + "," + ('%.4f' % datatemp[1]) + "," +
        #               ('%.6f' % datatemp[2]) + "," + ('%.4f' % datatemp[3])+"," +
        #               str(lasttick2) + "," + ('%.6f' % datatemp[4]) + "," + ('%.4f' % datatemp[5]) + "," +
        #               ('%.6f' % datatemp[6]) + "," + ('%.4f' % datatemp[7]) +"," +
        #               str(lasttick3) + "," + ('%.6f' % datatemp[8]) + "," + ('%.4f' % datatemp[9]) + "," +
        #               ('%.6f' % datatemp[10]) + "," + ('%.4f' % datatemp[11]))
        #         print("当前点," + str(pts.UpContainer) + "," +
        #               str(UpContainer1) + "," + ('%.6f' % pts.ChannelV[0]) + "," + ('%.4f' % pts.ChannelV[1]) + "," +
        #               ('%.6f' % pts.ChannelV[2]) + "," + ('%.4f' % pts.ChannelV[3]) +"," +
        #               str(UpContainer2) + "," + ('%.6f' % pts.ChannelV[16]) + "," + ('%.4f' % pts.ChannelV[17]) + "," +
        #               ('%.6f' % pts.ChannelV[18]) + "," + ('%.4f' % pts.ChannelV[19]) +"," +
        #               str(UpContainer3) + "," + ('%.6f' % pts.ChannelV[32]) + "," + ('%.4f' % pts.ChannelV[33]) + "," +
        #               ('%.6f' % pts.ChannelV[34]) + "," + ('%.4f' % pts.ChannelV[35]))
        #     if lasttick1 == UpContainer1 or lasttick3 == UpContainer3:
        #         print(datetime.datetime.now().strftime("%H:%M:%S") + "上一点," + str(lasttick) + "," +
        #               str(lasttick1) + "," + ('%.6f' % datatemp[0]) + "," + ('%.4f' % datatemp[1]) + "," +
        #               ('%.6f' % datatemp[2]) + "," + ('%.4f' % datatemp[3]) +"," +
        #               str(lasttick2) + "," + ('%.6f' % datatemp[4]) + "," + ('%.4f' % datatemp[5]) + "," +
        #               ('%.6f' % datatemp[6]) + "," + ('%.4f' % datatemp[7]) +"," +
        #               str(lasttick3) + "," + ('%.6f' % datatemp[8]) + "," + ('%.4f' % datatemp[9]) + "," +
        #               ('%.6f' % datatemp[10]) + "," + ('%.4f' % datatemp[11]))
        #         print("当前点," + str(pts.UpContainer) + "," +
        #               str(UpContainer1) + "," + ('%.6f' % pts.ChannelV[0]) + "," + ('%.4f' % pts.ChannelV[1]) + "," +
        #               ('%.6f' % pts.ChannelV[2]) + "," + ('%.4f' % pts.ChannelV[3]) +"," +
        #               str(UpContainer2) + "," + ('%.6f' % pts.ChannelV[16]) + "," + ('%.4f' % pts.ChannelV[17]) + "," +
        #               ('%.6f' % pts.ChannelV[18]) + "," + ('%.4f' % pts.ChannelV[19]) +"," +
        #               str(UpContainer3) + "," + ('%.6f' % pts.ChannelV[32]) + "," + ('%.4f' % pts.ChannelV[33]) + "," +
        #               ('%.6f' % pts.ChannelV[34]) + "," + ('%.4f' % pts.ChannelV[35]))
        #
        # datatemp.clear()
        # datatemp.append(pts.ChannelV[0])
        # datatemp.append(pts.ChannelV[1])
        # datatemp.append(pts.ChannelV[2])
        # datatemp.append(pts.ChannelV[3])
        # datatemp.append(pts.ChannelV[16])
        # datatemp.append(pts.ChannelV[17])
        # datatemp.append(pts.ChannelV[18])
        # datatemp.append(pts.ChannelV[19])
        # datatemp.append(pts.ChannelV[32])
        # datatemp.append(pts.ChannelV[33])
        # datatemp.append(pts.ChannelV[34])
        # datatemp.append(pts.ChannelV[35])
        # lasttick1 = UpContainer1
        # lasttick2 = UpContainer2
        # lasttick3 = UpContainer3
        # lasttick = pts.UpContainer
        # endregion
        self.sigReceive.emit(pts)

    def info(self, s, emit=True):
        if emit:
            self.sigInfo.emit(s)
            log.debug("采集", s)
        print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + " " + str(
            threading.currentThread().ident) + " " + s)

    def inverseSignal(self, i, b):
        """设置通道信号是否翻转"""
        if i < len(self.inverse):
            self.inverse[i] = b
